"""
UDP API
@Author: CsCN
"""

import socket
import time
import json
import threading
import re

import myConfig


class MyUDPSocket:
    """
    局域网Socket, 需要设置局域网网段
    """
    net: str  # 192.168.180.1/24
    recvFlag = True
    udp_socket: socket.socket
    recv_broadcast_socket: socket.socket
    send_broadcast_socket: socket.socket

    def __init__(self, net: str):
        self.net = net
        self.myip = net.split('/')[0]
        broadcast_addr = self.myip.split('.')
        for i in range(int(net.split('/')[-1]) // 8, 4):
            broadcast_addr[i] = '255'
        self.broadcast_addr = '.'.join(broadcast_addr)
        self.udp_socket = self.getUdpSocket()

    def getUdpSocket(self):
        """
        获得udpSocket
        :return: socket
        """
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.settimeout(myConfig.baseTimeout)
        sock.bind((self.myip, myConfig.commonPort))
        return sock

    def close(self):
        """
        优雅地关闭所有socket
        """
        self.recvFlag = False
        time.sleep(myConfig.baseTimeout)
        self.udp_socket.close()
        self.send_broadcast_socket.close()
        self.recv_broadcast_socket.close()

    def sendBroadcast(self, text: str):
        """
        发送局域网广播
        """
        print(self.broadcast_addr)
        print(text)
        self.send_broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.send_broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.send_broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.send_broadcast_socket.bind((self.myip, myConfig.broadcastPort))
        for _ in range(3):
            self.send_broadcast_socket.sendto(text.encode(myConfig.encoding),
                                              (self.broadcast_addr, myConfig.broadcastPort))
            time.sleep(1)
        # print('send ok')

    def recvBroadcast(self):
        """
        接收局域网广播信息
        @:return data: str, addr: tuple[str, int]
        """
        self.recv_broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.recv_broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.recv_broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.recv_broadcast_socket.bind(('', myConfig.broadcastPort))
        self.recv_broadcast_socket.settimeout(myConfig.baseTimeout)
        # print('comeon')
        while self.recvFlag:
            try:
                data, addr = self.recv_broadcast_socket.recvfrom(1024)
            except socket.timeout:
                continue
            # print(f"recv from {addr}")
            return data.decode(myConfig.encoding), addr
        return None

    def send_str(self, sendTo: tuple, message: str) -> None:
        """
        发送字符串
        :param sendTo: (ip, port)
        :param message: 需要发送的字符串
        """
        try:
            self.udp_socket.sendto(message.encode(myConfig.encoding), sendTo)
            # print(f"send {message} to {sendTo}")
        except Exception as e:
            print(e.args)

    def send_json(self, sendTo: tuple, jsonMsg: dict) -> None:
        """
        发送json
        :param sendTo: (ip, port)
        :param jsonMsg: 需要发送的字典
        """
        msg = json.dumps(jsonMsg)  # dict to json str
        self.send_str(sendTo, msg)

    def recv_str(self):
        """
        接收字符串
        :return: 收到的字符串数据str, 发送者地址tuple[ip(str), port(int)]
        """
        try:
            # udp_socket = self.getUdpSocket()
            while self.recvFlag:
                # print('recv')
                try:
                    data_bytes, addr = self.udp_socket.recvfrom(1024)
                except socket.timeout:
                    continue
                # print('recvdddddddd')
                data_str = data_bytes.decode(myConfig.encoding)
                return data_str, addr
            # self.udp_socket.close()
        except Exception as e:
            print(e.args)

    def recv_json(self):
        """
        接收json
        :return: 字典型数据, 发送者地址
        """
        data_str, addr = self.recv_str()
        data_dict = json.loads(data_str)
        return data_dict, addr

